package com.gxa.community.admin.service.order.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gxa.community.admin.mapper.agent.UserAgentApplicationMapper;
import com.gxa.community.admin.mapper.order.AfterSalesMapper;
import com.gxa.community.admin.mapper.order.OrderInfoMapper;
import com.gxa.community.admin.mapper.order.UserInfoMapper;
import com.gxa.community.admin.service.order.AfterSalesService;
import com.gxa.community.core.pojo.bo.order.AfterSalesNoAndReason;
import com.gxa.community.core.pojo.domain.AfterSales;
import com.gxa.community.core.pojo.domain.OrderInfo;
import com.gxa.community.core.pojo.domain.UserAgentApplication;
import com.gxa.community.core.pojo.domain.UserInfo;
import com.gxa.community.core.pojo.vo.order.AfterSalesVo;
import com.gxa.community.core.pojo.vo.order.OrderInfoVo;
import com.gxa.community.core.utils.LittleUtils;
import com.gxa.community.core.utils.R;
import org.springframework.stereotype.Service;

import java.util.*;

import static java.util.stream.Collectors.toSet;


@Service
public class AfterSalesServiceImpl implements AfterSalesService {

    final AfterSalesMapper afterSalesMapper;
    final UserAgentApplicationMapper agentInfoMapper;
    final UserInfoMapper userInfoMapper;
    final OrderInfoMapper orderInfoMapper;

    public AfterSalesServiceImpl(AfterSalesMapper afterSalesMapper, UserAgentApplicationMapper userAgentApplicationMapper, UserInfoMapper userInfoMapper, OrderInfoMapper orderInfoMapper) {
        this.afterSalesMapper = afterSalesMapper;
        this.agentInfoMapper = userAgentApplicationMapper;
        this.userInfoMapper = userInfoMapper;
        this.orderInfoMapper = orderInfoMapper;
    }

    /**
     * 查询售后申请列表
     */
    @Override
    public R queryAfterSales(Integer page, Integer size, AfterSalesVo afterSalesVo) {
        Page<AfterSales> infoPage = new Page<>(page, size);
        // 通过自提点类型/自提点名称查询用户id
        Set<Object> userIds = new HashSet<>();
        if (StringUtils.isNotBlank(afterSalesVo.getPoint()) || afterSalesVo.getPointType() != null)
            userIds.addAll(new HashSet<>(agentInfoMapper.selectObjs(new QueryWrapper<UserAgentApplication>().select("user_id")
                    .like(StringUtils.isNotBlank(afterSalesVo.getPoint()), "island_name", afterSalesVo.getPoint())
                    .eq(afterSalesVo.getPointType() != null, "island_type", afterSalesVo.getPointType())
                    .eq("status", 1))));

        // 通过用户名查询用户id
        if (StringUtils.isNotBlank(afterSalesVo.getUserNick()))
            userIds.addAll(new HashSet<>(userInfoMapper.selectObjs(new QueryWrapper<UserInfo>().select("user_id")
                    .like("nick_name", afterSalesVo.getUserNick()))));

        // 查询售后基础信息
        Page<AfterSales> afterSalesPage = new LambdaQueryChainWrapper<>(afterSalesMapper)
                .eq(afterSalesVo.getUserId() != null, AfterSales::getUserId, afterSalesVo.getUserId())
                .in(!userIds.isEmpty(), AfterSales::getUserId, userIds)
                .eq(StringUtils.isNotBlank(afterSalesVo.getOrderNo()), AfterSales::getOrderNo, afterSalesVo.getOrderNo())
                .eq(StringUtils.isNotBlank(afterSalesVo.getNo()), AfterSales::getNo, afterSalesVo.getNo())
                .eq(afterSalesVo.getAsType() != null, AfterSales::getType, afterSalesVo.getAsType())
                .eq(afterSalesVo.getStatus() != null, AfterSales::getStatus, afterSalesVo.getStatus())
                .page(infoPage);

        List<AfterSales> afterSales = afterSalesPage.getRecords();

        if (afterSales == null || afterSales.isEmpty())
            return R.page(afterSalesPage.getCurrent(), afterSalesPage.getSize(), afterSalesPage.getTotal(), new ArrayList<>());

        // 查询售后关联的订单信息
        HashMap<String, OrderInfoVo> orderInfos =
                orderInfoMapper.selectList(Wrappers.lambdaQuery(OrderInfo.class)
                                .in(OrderInfo::getNos, afterSales.stream().map(AfterSales::getOrderNo).collect(toSet())))
                        .stream().collect(HashMap::new, (map, order) -> map.put(order.getNos(), orderToVo(order)), HashMap::putAll);

        List<AfterSalesVo> afterSalesVos = new ArrayList<>();
        for (AfterSales afterSale : afterSales) {
            afterSalesVos.add(
                    new AfterSalesVo()
                            .setNo(afterSale.getNo())
                            .setUserId(afterSale.getUserId())
                            .setOrderInfo(orderInfos.get(afterSale.getOrderNo()))
                            .setDesc(afterSale.getTips())
                            .setType(afterSale.getType())
                            .setRequestReason(afterSale.getRequestReason())
                            .setRequestRefund(afterSale.getRequestRefund())
                            .setPic(afterSale.getPic())
                            .setCreateTime(afterSale.getCreateTime())
                            .setReviewTime(afterSale.getReviewTime())
                            .setRefundTime(afterSalesVo.getRefundTime())
                            .setRefund(afterSale.getRefund())
                            .setRejectReason(afterSalesVo.getRejectReason())
                            .setStatus(afterSalesVo.getStatus())
            );
        }

        return R.page(afterSalesPage.getCurrent(), afterSalesPage.getSize(), afterSalesPage.getTotal(), afterSalesVos);
    }

    /**
     * 批量同意售后申请
     * 并处理退款
     *
     * @param nos 售后单号
     */
    @Override
    public R agreeAfterSales(List<String> nos) {

        if (afterSalesMapper.selectCount(Wrappers.lambdaQuery(AfterSales.class)
                .in(AfterSales::getNo, nos)
        ) == 0) return R.error("售后单号不存在");

        if (afterSalesMapper.update(new AfterSales().setStatus(2).setReviewTime(System.currentTimeMillis())
                , Wrappers.lambdaUpdate(AfterSales.class).in(AfterSales::getNo, nos)) > 0) {
            // 根据售后单号查询售后信息
            List<AfterSales> afterSales = afterSalesMapper.selectList(Wrappers.lambdaQuery(AfterSales.class).in(AfterSales::getNo, nos));
            for (AfterSales afterSale : afterSales) {
                double refund;
                // 退款
                int back = userInfoMapper.update(
                        new UserInfo().setBalance(
                                // 计算退款后账户余额
                                userInfoMapper.selectOne(
                                        Wrappers.lambdaQuery(UserInfo.class).eq(UserInfo::getUserId, afterSale.getUserId())
                                ).getBalance() + (refund = afterSale.getRequestRefund() - afterSale.getRefund()))
                        , Wrappers.lambdaUpdate(UserInfo.class).eq(UserInfo::getUserId, afterSale.getUserId()));

                if (back <= 0) return R.error("退款失败");

                // 修改退款时间 以及 退款金额
                back = afterSalesMapper.update(
                        new AfterSales().setReviewTime(System.currentTimeMillis()).setRefund(refund)
                        , Wrappers.lambdaUpdate(AfterSales.class)
                                .eq(AfterSales::getNo, afterSale.getNo())
                                .eq(AfterSales::getRefund, 0)
                                .eq(AfterSales::getStatus, 2)
                );

                if (back <= 0) return R.error("退款异常");
            }
            return R.ok();
        }
        return R.error("售后申请单处理失败");
    }

    /**
     * 批量拒绝售后申请
     *
     * @param nos nos 售后单号, rejectReason 拒绝原因
     */
    @Override
    public R rejectAfterSales(AfterSalesNoAndReason nos) {

        if (afterSalesMapper.selectCount(Wrappers.lambdaQuery(AfterSales.class)
                .in(AfterSales::getNo, nos.getNos())
        ) == 0) return R.error("售后单号不存在");

        if (afterSalesMapper.update(new AfterSales().setStatus(3)
                        .setRejectReason(nos.getRejectReason())
                        .setReviewTime(System.currentTimeMillis())
                , Wrappers.lambdaUpdate(AfterSales.class).in(AfterSales::getNo, nos.getNos())) > 0) {
            return R.ok();
        }
        return R.error("售后申请单处理失败");
    }

    /**
     * 添加售后
     *
     * @param salesVo orderNo 订单编号
     *                type 售后类型 1未收到货-仅退款 2少件/漏件 3其他
     *                desc 问题描述
     *                pic 照片地址
     *                requestReason 退款原因  1包装破损 2商品质量问题 3发错货 4商品与描述不符 5其他
     *                requestRefund 申请退款金额
     */
    @Override
    public R addAfterSales(AfterSalesVo salesVo) {

        // 获取订单信息, 判断申请金额是否合法
        OrderInfo orderInfo = orderInfoMapper.selectOne(
                Wrappers.lambdaQuery(OrderInfo.class)
                        .eq(OrderInfo::getNos, salesVo.getOrderNo())
        );

        if (orderInfo == null) return R.error("订单不存在");

        Double payment = orderInfo.getPayment().doubleValue();

        if (payment == null) return R.error("订单信息有误");
        if (payment < salesVo.getRequestRefund()) return R.error("申请退款金额不能大于实际支付金额");

        Long timestamp = System.currentTimeMillis();
        if (afterSalesMapper.insert(new AfterSales()
                .setUserId(salesVo.getUserId())
                .setNo(LittleUtils.generateNo(16, timestamp))
                .setCreateTime(timestamp)
                .setOrderNo(salesVo.getOrderNo())
                .setType(salesVo.getType())
                .setTips(salesVo.getDesc())
                .setPic(salesVo.getPic())
                .setRequestReason(salesVo.getRequestReason())
                .setRequestRefund(salesVo.getRequestRefund())
        ) > 0)
            return R.ok();
        return R.error("售后申请失败");
    }

    private OrderInfoVo orderToVo(OrderInfo orderInfo) {
        return new OrderInfoVo()
                .setNo(orderInfo.getNos())
                .setCreateTime(orderInfo.getCreateTime())
                .setPayment(orderInfo.getPayment().doubleValue());
    }
}
